// UberViewerView.cpp : implementation file
//

#include "stdafx.h"
#include "UberViewer.h"
#include "UberViewerView.h"
#include "MainFrm.h"
#include "UberViewerDoc.h"

#include <list>

bool firstTime = false;

// CUberViewerView

IMPLEMENT_DYNCREATE(CUberViewerView, COpenGLView)

CUberViewerView::CUberViewerView()
{
	TRACE("CUberViewerView::CUberViewerView");

//	m_pModelManager = ((CMainFrame*)AfxGetMainWnd())->GetModelManager();
//	m_pTextureManager = ((CMainFrame*)AfxGetMainWnd())->GetTextureManager();

//	CString str = "CUberViewerView::CUberViewerView m_pDocument = "; str.AppendFormat("%d", (int) m_pDocument);
//	AfxMessageBox(str);
}

CUberViewerView::~CUberViewerView()
{
	TRACE("CUberViewerView::~CUberViewerView");
}

BEGIN_MESSAGE_MAP(CUberViewerView, COpenGLView)
    ON_COMMAND(ID_VIEW_OPENSTREETMAP, OnSetOSmap) 
    ON_UPDATE_COMMAND_UI(ID_VIEW_OPENSTREETMAP, OnUpdateOSmap) 
	ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()


// CUberViewerView drawing


void SetMaterial(SMaterial *mtrl)
{
	if (mtrl->texture != NULL)
	{
		float ambient[] = {1.0, 1.0, 1.0, 1.0};
		float specular[] = {0.1, 0.1, 0.1, 1.0};
		float shininess = 0.3f;

		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ambient);
        glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
        glMaterialf (GL_FRONT, GL_SHININESS, shininess);
		glBindTexture(GL_TEXTURE_2D, mtrl->texture->m_OpenglId);
	}
	else
	{
		float ambient[] = {1.0, 0.0, 0.0, 1.0f};
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mtrl->diffuse);
		glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mtrl->emissive);
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mtrl->specular);
		glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, mtrl->shininess);
		glMaterialf (GL_FRONT_AND_BACK, GL_ALPHA, mtrl->diffuse[3]);
	}
}


void CUberViewerView::InitializeTextures()
{
//	TRACE("CUberViewerView::CUberViewerView");

	int w, h, f;
	BYTE *data;

	if (gTextureManager.m_updateOGL)
	{
		std::list<CTexture*>::iterator it = gTextureManager.m_textures.begin();
		for (; it != gTextureManager.m_textures.end(); ++it)
		{
			if ((*it)->m_changed)
			{
				(*it)->OpenTextureData(&w, &h, &f, &data); 
				if ((*it)->m_OpenglId == 0)	
					(*it)->m_OpenglId = AddTexture(w, h, f, data);
				else
					ReplaceTexture((*it)->m_OpenglId, w, h, f, data);
				(*it)->CloseTextureData(); 
				(*it)->m_changed = false;
			}
		}
	}
}


void CUberViewerView::RenderOpaque(CModel *model)
{
	S3DObject	*object = model->m_p3DObject;
	SPolygon    *polygon;
	while  (object) 
	{
		polygon = object->polygon;
		while (polygon)
		{
			if	(object->visible && polygon->primitiveCount > 0 && polygon->mtrl->diffuse[3] > 0.999)
			{
				SetMaterial(polygon->mtrl);
				glBegin(GL_TRIANGLES);
				for (int l = 0; l < polygon->primitiveCount * 3; l++)
				{
					if (model->m_type == MT_GML && polygon->mtrl->texture != NULL)
						glTexCoord2f(((CGmlModel*)model)->m_pTexMap[model->m_pIndices[polygon->startIndex + l]].x,
							         ((CGmlModel*)model)->m_pTexMap[model->m_pIndices[polygon->startIndex + l]].y);					

					glNormal3f(model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].nx, 
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].ny,
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].nz);
					glVertex3f(model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].x, 
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].y,
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].z);
				}
				glEnd();
			}
			polygon = polygon->next;
		}
		object = object->next;
	}
}

void CUberViewerView::RenderTransp(CModel *model)
{
	S3DObject	*object = model->m_p3DObject;
	SPolygon    *polygon;
	while  (object) 
	{
		polygon = object->polygon;
		while (polygon)
		{
			if	(object->visible && polygon->primitiveCount > 0 && polygon->mtrl->diffuse[3] <= 0.999)
			{
				SetMaterial(polygon->mtrl);
				glBegin(GL_TRIANGLES);
				for (int l = 0; l < polygon->primitiveCount * 3; l++)
				{
					if (object->type == MT_GML && polygon->mtrl->texture != NULL)
						glTexCoord2f(((CGmlModel*)model)->m_pTexMap[model->m_pIndices[polygon->startIndex + l]].x,
							         ((CGmlModel*)model)->m_pTexMap[model->m_pIndices[polygon->startIndex + l]].y);					

					glNormal3f(model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].nx, 
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].ny,
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].nz);
					glVertex3f(model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].x, 
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].y,
						       model->m_pVertices[model->m_pIndices[polygon->startIndex + l]].z);
				}
				glEnd();
			}
			polygon = polygon->next;
		}
		object = object->next;
	}
}

/*
void CUberViewerView::RenderGml(CGmlModel *gml)
{
	SGml3DObject	*instance = gml->m_p3DObjects;
	SGmlPolygon     *poly;
	while  (instance) 
	{
		poly = instance->polygons;
		while (poly)
		{
			if (poly->texture != NULL)
			{
				SetMaterial(1.0f, 1.0f, 1.0f, 1.0f);
				glBindTexture(GL_TEXTURE_2D, poly->texture->m_OpenglId);
			}
			else if (poly->mtrl > 0)
			{
				D3DMATERIAL8 *mtrl = gml->GetMaterial(poly->mtrl);
				SetMaterial(mtrl->Ambient.r, mtrl->Ambient.g, mtrl->Ambient.b, mtrl->Ambient.a);		
			}
			glNormal3f(((CUSTOMVERTEX*)gml->m_pVertices)[poly->startVertex].nx,
				((CUSTOMVERTEX*)gml->m_pVertices)[poly->startVertex].ny,
				((CUSTOMVERTEX*)gml->m_pVertices)[poly->startVertex].nz);
			
			glBegin(GL_TRIANGLES);
			for (int l = poly->startIndex; l < poly->startIndex + (poly->primitiveCount * 3); l++)
			{
				if (poly->texture != NULL)
					glTexCoord2f(gml->m_pTexMap[l * 2], gml->m_pTexMap[l * 2 + 1]);					

				glVertex3f(((CUSTOMVERTEX*)gml->m_pVertices)[l].x, 
					((CUSTOMVERTEX*)gml->m_pVertices)[l].y,
					((CUSTOMVERTEX*)gml->m_pVertices)[l].z);
			}
			glEnd();
			poly = poly->next;
		}
		instance = instance->next;
	}

/*
	const citygml::CityObjectsMap& cityObjectsMap =  gml->m_modelRef->getCityObjectsMap();

	citygml::CityObjectsMap::const_iterator it = cityObjectsMap.begin();

	for ( ; it != cityObjectsMap.end(); it++ )
	{
		const citygml::CityObjects& v = it->second;

		for ( unsigned int i = 0; i < v.size(); i++ )
		{
			const citygml::CityObject* object = v[i];
			SetMaterial(object->getDefaultColor().r, object->getDefaultColor().g, object->getDefaultColor().b);

			for (int n = 0; n < object->size(); n++)
			{
				const citygml::Geometry& geo = *object->getGeometry(n);
				for (int k = 0; k < geo.size(); k++)
				{
					const citygml::Polygon *p = geo[k];
					if ( !p || !p->getIndices() || p->getIndicesSize() == 0 ) continue;

					const citygml::Appearance *mat = p->getAppearance();
					const citygml::TexCoords *texCoords = NULL;

					if ( mat )
					{
						if ( const citygml::Material* m = dynamic_cast<const citygml::Material*>( mat ) )
						{
							float diffuse[4]  = {m->getDiffuse().r, m->getDiffuse().g, m->getDiffuse().b, 1.f };
							float emissive[4] = {m->getEmissive().r, m->getEmissive().g, m->getEmissive().b, 1.f };
							float specular[4] = {m->getSpecular().r, m->getSpecular().g, m->getSpecular().b, 1.f };
							float ambient[4]  = {m->getAmbientIntensity(), m->getAmbientIntensity(), m->getAmbientIntensity(), 1.f};

							glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*)diffuse);
							glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*)emissive);
							glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*)specular);
							glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*)ambient);
						}
						else if ( const citygml::Texture* t = dynamic_cast<const citygml::Texture*>( mat ) ) 
						{
							CString url = gml->m_filePath;
							url += t->getUrl().c_str();

							texCoords = p->getTexCoords();

							unsigned int id = gTextureManager.GetTextureId(url);

							if (id > 0)
							{
								SetMaterial(1.0f, 1.0f, 1.0f);
								glBindTexture(GL_TEXTURE_2D, id);
							}
						}
					}

					glBegin(GL_TRIANGLES);
					glNormal3f(p->getNormal().x, p->getNormal().y, p->getNormal().z);
					for (int l = 0; l < p->getIndicesSize(); l++)
					{
						if (texCoords)
							glTexCoord2f((*texCoords)[p->getIndices()[l]].x, (*texCoords)[p->getIndices()[l]].y);					
						glVertex3f((*p)[p->getIndices()[l]][0], (*p)[p->getIndices()[l]][1], (*p)[p->getIndices()[l]][2]);
					}
					glEnd();
				}
			}
		}
	}
	*
}
*/


void CUberViewerView::RenderScene()
{
//	TRACE("CUberViewerView(%s)::RenderScene", ((CString)(GetDocument()->GetTitle())).GetBuffer());

	CUberViewerDoc *doc = (CUberViewerDoc*) GetDocument();

	if (doc != NULL) 
	{
		InitializeTextures();

		// Draw the card
		if (doc->m_OSmap && doc->m_ShowOSmap)
		{
			float color[4] = {1.0, 1.0, 1.0, 1.0};
			glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
			glBindTexture(GL_TEXTURE_2D, doc->m_OSmap->m_OpenglId);
			glBegin(GL_QUADS);
			glNormal3f(0.0f, 0.0f, 1.0f);
			glTexCoord2f(0,0);
			glVertex3f( -1000.0f, -1000.0f, -0.01f);		// Top Of Triangle (Front)
			glTexCoord2f(1,0);
			glVertex3f( 1000.0f, -1000.0f, -0.01f);			// Top Of Triangle (Front)
			glTexCoord2f(1,1);
			glVertex3f( 1000.0f, 1000.0f, -0.01f);			// Top Of Triangle (Front)
			glTexCoord2f(0,1);
			glVertex3f( -1000.0f, 1000.0f, -0.01f);			// Top Of Triangle (Front)
			glEnd();
		}

		// Draw opaque
		std::list<InstantiatedModel*>::iterator it = doc->m_instantiatedModels.begin();
		for ( ; it != doc->m_instantiatedModels.end(); it++)
		{
			if ((*it)->pModel->m_type == MT_IFC)
				glScalef(((CIfcModel*)(*it)->pModel)->m_unitScale, ((CIfcModel*)(*it)->pModel)->m_unitScale, ((CIfcModel*)(*it)->pModel)->m_unitScale);
			glTranslatef((*it)->location.m_xOffset, (*it)->location.m_yOffset, 0.0);
			glRotatef((*it)->location.m_orientation, 0.0, 0.0, -1.0);
			RenderOpaque((*it)->pModel);
			glRotatef((*it)->location.m_orientation, 0.0, 0.0, 1.0);
			glTranslatef(-(*it)->location.m_xOffset, -(*it)->location.m_yOffset, 0.0);
			if ((*it)->pModel->m_type == MT_IFC)
				glScalef(1.0 / ((CIfcModel*)(*it)->pModel)->m_unitScale, 1.0 / ((CIfcModel*)(*it)->pModel)->m_unitScale, 1.0 / ((CIfcModel*)(*it)->pModel)->m_unitScale);
		}

		// Draw transparent
		for (it = doc->m_instantiatedModels.begin(); it != doc->m_instantiatedModels.end(); it++)
		{
			if ((*it)->pModel->m_type == MT_IFC)
				glScalef(((CIfcModel*)(*it)->pModel)->m_unitScale, ((CIfcModel*)(*it)->pModel)->m_unitScale, ((CIfcModel*)(*it)->pModel)->m_unitScale);
			glTranslatef((*it)->location.m_xOffset, (*it)->location.m_yOffset, 0.0);
			glRotatef((*it)->location.m_orientation, 0.0, 0.0, -1.0);
			RenderTransp((*it)->pModel);
			glRotatef((*it)->location.m_orientation, 0.0, 0.0, 1.0);
			glTranslatef(-(*it)->location.m_xOffset, -(*it)->location.m_yOffset, 0.0);
			if ((*it)->pModel->m_type == MT_IFC)
				glScalef(1.0 / ((CIfcModel*)(*it)->pModel)->m_unitScale, 1.0 / ((CIfcModel*)(*it)->pModel)->m_unitScale, 1.0 / ((CIfcModel*)(*it)->pModel)->m_unitScale);
		}
	}
	firstTime = false;
}



void CUberViewerView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	TRACE("COpenGLView::OnLButtonDblClk");
//	CString str = "COpenGLView::OnLButtonDblClk m_pDocument = "; str.AppendFormat("%d", (int) m_pDocument);
//	AfxMessageBox(str);
//	firstTime = true;


//	CheckPick(point);

//	if (CheckPick(point))
//	{
//		SelectionChanged();
//	}
	GetParent()->Invalidate();
//	((CMainFrame*) GetParentFrame())->m_wndObjectView->SelectedObject();
}



// CUberViewerView diagnostics

#ifdef _DEBUG
void CUberViewerView::AssertValid() const
{
	CView::AssertValid();
}

void CUberViewerView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif //_DEBUG


CUberViewerDoc* CUberViewerView::GetDocument() 
{
//    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CYourAppDoc)));
//	AfxMessageBox(((CUberViewerDoc*)m_pDocument)->m_OSmap->m_URI);

	return (CUberViewerDoc*) m_pDocument;
} 


// CUberViewerView message handlers

void CUberViewerView::OnSetOSmap() 
{ 
	TRACE("CUberViewerView::OnSetOSmap");

	CUberViewerDoc *doc = (CUberViewerDoc*) GetDocument();
	if (doc != NULL) 
	{
		doc->m_ShowOSmap = !doc->m_ShowOSmap;
	}
	Invalidate(); 
} 
 
void CUberViewerView::OnUpdateOSmap(CCmdUI* pCmdUI) 
{ 
	TRACE("CUberViewerView::OnUpdateOSmap");

	CUberViewerDoc *doc = (CUberViewerDoc*) GetDocument();
	if (doc != NULL) 
	{
		pCmdUI->SetCheck(doc->m_ShowOSmap);
	}
} 
